package com.rent.common.aop;

import cn.hutool.core.util.IdUtil;
import com.rent.common.annotation.AvoidRepeatableCommit;
import com.rent.common.pojo.ResultJSON;
import com.rent.common.utils.CommonUtil;
import com.rent.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

/**
 * @Author zhang
 * @create 2022/4/14 13:59
 * 防重提交切面
 */
@Slf4j
@Order(-1)
@Aspect
@Component
public class AvoidRepeatableCommitAspect {

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * @param point 切点
     */
    @Around("@annotation(com.rent.common.annotation.AvoidRepeatableCommit)")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
        String ip = CommonUtil.getIPAddress(request);
        //获取注解
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        //目标类、方法
        String className = method.getDeclaringClass().getName();
        String name = method.getName();
        String ipKey = String.format("%s#%s", className, name);
        int hashCode = Math.abs(ipKey.hashCode());
        String key = String.format("%s_%d", ip, hashCode);
        log.info("ipKey={},hashCode={},key={}", ipKey, hashCode, key);
        AvoidRepeatableCommit avoidRepeatableCommit = method.getAnnotation(AvoidRepeatableCommit.class);
        // 不做重复处理
        if (!avoidRepeatableCommit.enabled()) return point.proceed();
        long timeout = avoidRepeatableCommit.timeout();
        if (timeout < 0) {
            //过期时间30秒
            timeout = 30 * 1000;
        }
        try {
            String value = redisTemplate.opsForValue().get(key);
            if (!StringUtils.isEmpty(value)) {
                return ResultJSON.failure(avoidRepeatableCommit.value());
            }
            redisTemplate.opsForValue().set(key, IdUtil.getSnowflakeNextIdStr(), timeout, TimeUnit.MILLISECONDS);
        } catch (Exception e) {
            log.info("redis取值异常");
        }
        //执行方法
        return point.proceed();
    }

}
